#ifndef T_AVCODEC_H
#define T_AVCODEC_H

#include "t_core.h"
extern "C"
{
#include "libavformat/avformat.h"
}

class T_AVImage
{
public:
    explicit T_AVImage() {  }
    virtual ~T_AVImage() {  }
    virtual enum PixelFormat pix_fmt() = 0;
    virtual int width() = 0;
    virtual int height() = 0;
    virtual uint8_t **data() = 0;
    virtual int *linesize() = 0;
};

class T_AVFrame : public T_AVImage
{
protected:
    AVCodecContext *m_codec_ctx;
    AVFrame *m_frame;
public:
    explicit T_AVFrame(AVCodecContext *a_codec_ctx);
    virtual ~T_AVFrame();
    virtual enum PixelFormat pix_fmt();
    virtual int width();
    virtual int height();
    virtual uint8_t **data();
    virtual int *linesize();
    AVCodecContext *codecContext();
    AVFrame *frame();
};

class T_AVPicture_Allocator
{
protected:
    enum PixelFormat m_pix_fmt;
    int m_width;
    int m_height;
    AVPicture m_avpicture;
public:
    explicit T_AVPicture_Allocator();
    virtual ~T_AVPicture_Allocator();
    enum PixelFormat &f_pix_fmt();
    int  &f_width();
    int  &f_height();
    AVPicture &f_avpicture();
    virtual void buffer_resize(size_t a_size) = 0;
    virtual size_t buffer_size() = 0;
    virtual uchar *buffer_top() = 0;
    virtual void attach() = 0;
    virtual void detach() = 0;
    void reallocate(PixelFormat a_pix_fmt, int a_width, int a_height);
protected:
    void p_refill(uchar *a_top);
};

class T_AVPicture_Base : public QObject, public T_AVImage
{
protected:
    T_DECLARE_PRIVATE(T_AVPicture_Base);
public:
    explicit T_AVPicture_Base(T_AVPicture_Allocator *a_allocator);
    virtual ~T_AVPicture_Base();
    virtual enum PixelFormat pix_fmt();
    virtual int width();
    virtual int height();
    virtual uint8_t **data();
    virtual int *linesize();
    void resize(PixelFormat a_pix_fmt, int a_width, int a_height);
    void resizeForQImage(int a_depth, int a_width, int a_height);
    void copyFrom(T_AVImage *a_image);
    void scaleFrom(T_AVImage *a_src, int a_sws_flags = SWS_FAST_BILINEAR);
    QImage toQImage();
};

class T_AVPicture_Allocator_Memory : public T_AVPicture_Allocator
{
protected:
    T_MemoryAligned m_buffer;
public:
    explicit T_AVPicture_Allocator_Memory() {  }
    virtual ~T_AVPicture_Allocator_Memory() {  }
    virtual void buffer_resize(size_t a_size) { Q_ASSERT(a_size>0); m_buffer.resize(a_size, 32); }
    virtual size_t buffer_size() { return m_buffer.size(); }
    virtual uchar *buffer_top() { return m_buffer.top(); }
    virtual void attach() {  }
    virtual void detach() {  }
};

class T_AVPicture : public T_AVPicture_Base, protected T_AVPicture_Allocator_Memory
{
public:
    explicit T_AVPicture(PixelFormat a_pix_fmt=PIX_FMT_YUV420P, int a_width=1, int a_height=1);
    explicit T_AVPicture(T_AVImage *a_image);
    virtual ~T_AVPicture();
};

class T_AVPicture_Allocator_MMF : public T_AVPicture_Allocator
{
protected:
    QFile *m_file;
    uchar *m_mapped;
    T_AtomicCounter32 m_counter;
public:
    explicit T_AVPicture_Allocator_MMF(QFile *a_file);
    virtual ~T_AVPicture_Allocator_MMF();
    virtual void buffer_resize(size_t a_size);
    virtual size_t buffer_size();
    virtual uchar *buffer_top();
    virtual void attach();
    virtual void detach();
protected:
    void p_remap();
    void p_unmap();
};

class T_AVPictureProxy : public T_AVPicture_Base
{
protected:
    T_AVPicture_Allocator *m_allocator;
public:
    explicit T_AVPictureProxy(T_AVPicture_Allocator *a_allocator)
        : T_AVPicture_Base(a_allocator)
        , m_allocator(a_allocator)
    {
        m_allocator->attach();
    }
    virtual ~T_AVPictureProxy()
    {
        m_allocator->detach();
    }
};

class T_AVPictureManager
{
public:
    explicit T_AVPictureManager() {  }
    virtual ~T_AVPictureManager() {  }
    virtual QSharedPointer<T_AVPictureProxy> proxy() = 0;
};

class T_AVPictureManager_MMF : public T_AVPictureManager
{
protected:
    QTemporaryFile *m_file;
    T_AVPicture_Allocator_MMF *m_allocator;
public:
    explicit T_AVPictureManager_MMF()
        : m_file(NULL)
        , m_allocator(NULL)
    {
        m_file = new QTemporaryFile("E:/MMF/ABC");
        m_file->open();
        m_allocator = new T_AVPicture_Allocator_MMF(m_file);
    }
    virtual ~T_AVPictureManager_MMF()
    {
        delete m_allocator;
        delete m_file;
    }
    virtual QSharedPointer<T_AVPictureProxy> proxy()
    {
        T_AVPictureProxy *v_image = new T_AVPictureProxy(m_allocator);
        return QSharedPointer<T_AVPictureProxy>(v_image);
    }
};

class T_AVPictureManager_Memory : public T_AVPictureManager
{
protected:
    T_AVPicture_Allocator_Memory m_allocator;
    QSharedPointer<T_AVPictureProxy> m_image;
public:
    explicit T_AVPictureManager_Memory()
    {
        T_AVPictureProxy *v_image = new T_AVPictureProxy(&m_allocator);
        m_image = QSharedPointer<T_AVPictureProxy>(v_image);
    }
    virtual ~T_AVPictureManager_Memory()
    {
    }
    virtual QSharedPointer<T_AVPictureProxy> proxy()
    {
        return m_image;
    }
};

class T_AVRational
{
public:
    qint64 num; ///< numerator
    qint64 den; ///< denominator
public:
    T_AVRational(AVRational &a_rational);
    T_AVRational operator*(qint64 a) const;
    T_AVRational& operator*=(qint64 a);
    T_AVRational operator/(qint64 a) const;
    T_AVRational& operator/=(qint64 a);
    qint64 toLongLong() const;
    double toDouble() const;
};

#endif // T_AVCODEC_H
